package ui;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;

import td.ArcherTower;
import td.CatapultTower;
import td.FireTrap;
import td.MagicStones;
import td.Map;
import td.OneTower;
import td.Tower;
import td.Trap;
import td.TwoTower;
import td.VineTrap;
import td.WindTrap;

/*
 * View class to represent the game.
 * Includes the fields with tower,traps,enemies and also a buy menu
 * and hp bar with mana display.
 * */
public class MapView extends JFrame implements Viewable{

	/*Labels to represent the menu's buttons, 
	 * and trap cooldowns*/
	protected Map map;
	public JLabel mana;
	public JLabel hp;
	public JLabel oneLabel;
	public JLabel archerLabel;
	public JLabel catapultLabel;
	public JLabel twoLabel;
	public JLabel vineLabel;
	public JLabel windLabel;
	public JLabel fireLabel;
	public JLabel blueLabel;
	public JLabel yellowLabel;
	public JLabel redLabel;
	public JLabel rainbowLabel;
	public JLabel vineCd;
	public JLabel windCd;
	public JLabel fireCd;
	/* Boolean variable to see if player 
	 * is currently shopping*/
	public boolean picked = false;
	/* Boolean variable to see if player
	 * is currently upgrading*/
	public boolean upgrading = false;
	
	public MapView(Map map1){
		super("TowerDefense");
		this.map=map1;
		setResizable(false);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		GridBagLayout grid = new GridBagLayout();
		GridBagConstraints gridc = new GridBagConstraints();
		setLayout(grid);
		
				
		/*Display map fields*/
		gridc.gridwidth = 1;
		int i = 0;
		int j = 0;
		gridc.anchor = GridBagConstraints.CENTER;
		for(i=0; i<map.fields.size(); i++){
			for(j =0; j<map.fields.get(i).size(); j++){
				gridc.gridx = j;
				gridc.gridy = i+1;
				/*Add mouselisteners to the fields, so we can place tower, 
				 * traps and stones and also sell towers*/
				((FieldView) map.fields.get(i).get(j).viewable).addMouseListener(new MouseAdapter() {
					@Override
					public void mouseClicked(MouseEvent e) {
						/*Check if player is about to place a tower or trap*/
						if(picked){
							if(!((FieldView) e.getSource()).field.isRoad){
								if(map.player.getSelected() instanceof Tower){
									if(!((FieldView) e.getSource()).field.hasTower){
										/* If it's not a road, the player picked a tower, and the field does not have a tower yet
										 * the player can place the tower here.*/
										((Tower) map.player.getSelected()).setPosition(((FieldView) e.getSource()).field);
										((Tower) map.player.getSelected()).inRange(((Tower) map.player.getSelected()).getPosition(), 0);
										map.player.placeTower(((FieldView) e.getSource()).field);
										map.viewable.update();
										picked = false;
									}
								}
							}else if(map.player.getSelected() instanceof Trap){
								if(!((FieldView) e.getSource()).field.hasTrap){
									/* If it's a road, the player picked a trap, and the field does not have a trap yet
									 * the player can place the trap here.*/
									((Trap) map.player.getSelected()).setPosition(((FieldView) e.getSource()).field);
									map.player.placeTrap(((FieldView) e.getSource()).field);
									map.viewable.update();
									picked = false;
								}
							}
						}
						/*Check if player is about to upgrade a tower or trap*/
						else if(upgrading){
							if(((FieldView) e.getSource()).field.isRoad){
								if(((FieldView) e.getSource()).field.hasTrap){
									if(!((FieldView) e.getSource()).field.getTrap().wasUpgraded){
										/* If it's a road, and the field has a trap which wasn't upgraded yet, the player
										 * can upgrade this trap*/
										map.player.placeMagicStone(((FieldView) e.getSource()).field.getTrap());
										map.viewable.update();
										upgrading=false;
									}
								}
							}
							else{
								if(((FieldView) e.getSource()).field.hasTower){
									/* If it's not a road, and the field has a tower, the player is asked
									 * which slot he wants to upgrade. If the slot has a stone already
									 * it's swapped to currently held one.*/
									Object[] options = {"Slot 1","Slot 2"};
									JFrame frame = new JFrame();
									int n = JOptionPane.showOptionDialog(frame,
											"Which slot do you want to upgrade?",
											"Tower upgrade",
											JOptionPane.YES_NO_OPTION,
											JOptionPane.QUESTION_MESSAGE,
											null,
											options,
											options[0]);
									map.player.placeMagicStone(((FieldView) e.getSource()).field.getTower(), n);
									map.viewable.update();
									upgrading=false;
								}
							}
						}
						/*Else the player can sell the tower from the field if it has any*/
						else{
							if(((FieldView) e.getSource()).field.hasTower){
								map.player.sellTower(((FieldView) e.getSource()).field.getTower());
							}
						}
					}
				});
				add((FieldView) map.fields.get(i).get(j).viewable, gridc);
			}
		}
		
		/*Display player's mana*/
		gridc.gridx = j+1;
		gridc.gridy = 0;
		gridc.gridwidth = 2;
		gridc.gridheight = 2;
		gridc.anchor = GridBagConstraints.PAGE_START;
		mana = new JLabel("Mana: "+map.player.getMana());
		mana.setForeground(Color.blue);
		mana.setFont(mana.getFont().deriveFont(16.0f));
		add(mana,gridc);
		
		/*Display player's hp*/
		gridc.anchor = GridBagConstraints.CENTER;
		hp = new JLabel("Hp: "+map.player.getHp());
		hp.setForeground(Color.red);
		hp.setFont(hp.getFont().deriveFont(16.0f));
		add(hp,gridc);
		
		/*Buy menu*/
		/*Towers*/
		gridc.anchor = GridBagConstraints.PAGE_END;
		JLabel towers = new JLabel("Towers");
		add(towers,gridc);	
		
		/*One tower*/
		gridc.gridx = j+1;
		gridc.gridy = 2;
		gridc.gridwidth = 1;
		gridc.gridheight = 2;
		gridc.anchor = GridBagConstraints.PAGE_START;
		Image image = Toolkit.getDefaultToolkit().getImage("Images/onetower.png");
		oneLabel = new JLabel(new ImageIcon(image));
		oneLabel.setToolTipText("<html>Damage: 3<br>Range: 2<br>Speed: 1<br>Cost: 30<br>Rainbow Upgrade: Sloweffect</html>");
		oneLabel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if(((JLabel) e.getSource()).isEnabled()){
					map.player.pickTower(new OneTower());
					picked = true;
				}
			}
		});
		add(oneLabel,gridc);
				
		/*One tower cost*/
		JLabel cost = new JLabel("30");
		cost.setForeground(Color.blue);
		gridc.anchor = GridBagConstraints.CENTER;
		add(cost, gridc);
		
		/*Catapult tower*/
		gridc.anchor = GridBagConstraints.PAGE_END;
		image = Toolkit.getDefaultToolkit().getImage("Images/catapulttower.png");
		catapultLabel = new JLabel(new ImageIcon(image));
		/*Tooltip for tower stats*/
		catapultLabel.setToolTipText("<html>Damage: 4(AoE)<br>Range: 2<br>Speed: 2<br>Cost: 50<br>Rainbow Upgrade: Firedamage</html>");
		catapultLabel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if(((JLabel) e.getSource()).isEnabled()){
					map.player.pickTower(new CatapultTower());
					picked = true;
				}
			}
		});
		add(catapultLabel,gridc);
		
		/*Catapult tower cost*/
		gridc.gridx = j+1;
		gridc.gridy = 4;
		gridc.gridwidth = 1;
		gridc.gridheight = 1;
		cost = new JLabel("50");
		cost.setForeground(Color.blue);
		gridc.anchor = GridBagConstraints.PAGE_START;
		add(cost, gridc);
		
		/*Archer tower*/
		gridc.gridx = j+2;
		gridc.gridy = 2;
		gridc.gridwidth = 1;
		gridc.gridheight = 2;
		gridc.anchor = GridBagConstraints.PAGE_START;
		image = Toolkit.getDefaultToolkit().getImage("Images/archertower.png");
		archerLabel = new JLabel(new ImageIcon(image));
		/*Tooltip for tower stats*/
		archerLabel.setToolTipText("<html>Damage: 2<br>Range: 3<br>Speed: 0,5<br>Cost: 40<br>Rainbow Upgrade: Critical</html>");
		archerLabel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if(((JLabel) e.getSource()).isEnabled()){
					map.player.pickTower(new ArcherTower());
					picked = true;
				}
			}
		});
		add(archerLabel,gridc);
	
		/*Archer tower cost*/
		cost = new JLabel("40");
		cost.setForeground(Color.blue);
		gridc.anchor = GridBagConstraints.CENTER;
		add(cost, gridc);
		
		/*Two tower*/
		gridc.anchor = GridBagConstraints.PAGE_END;
		image = Toolkit.getDefaultToolkit().getImage("Images/twotower.png");
		twoLabel = new JLabel(new ImageIcon(image));
		/*Tooltip for tower stats*/
		twoLabel.setToolTipText("<html>Damage: 5<br>Range: 3<br>Speed: 1<br>Cost: 70<br>Rainbow Upgrade: Dual shot</html>");
		twoLabel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if(((JLabel) e.getSource()).isEnabled()){
					map.player.pickTower(new TwoTower());
					picked = true;
				}
			}
		});
		add(twoLabel,gridc);
		
		/*Two tower cost*/
		gridc.gridx = j+2;
		gridc.gridy = 4;
		gridc.gridwidth = 1;
		gridc.gridheight = 1;
		cost = new JLabel("70");
		cost.setForeground(Color.blue);
		gridc.anchor = GridBagConstraints.PAGE_START;
		add(cost, gridc);
		
		/*Traps*/
		gridc.gridx = j+1;
		gridc.gridy = 4;
		gridc.gridwidth = 2;
		gridc.anchor = GridBagConstraints.PAGE_END;
		JLabel traps = new JLabel("Traps");
		add(traps,gridc);
		
		/*Vine trap*/
		gridc.gridx = j+1;
		gridc.gridy = 5;
		gridc.gridwidth = 1;
		gridc.gridheight = 2;
		gridc.anchor = GridBagConstraints.PAGE_START;
		image = Toolkit.getDefaultToolkit().getImage("Images/vinetrap.png");
		vineLabel = new JLabel(new ImageIcon(image));
		/*Tooltip for trap stats*/
		vineLabel.setToolTipText("<html>Slows down enemies<br>Rainbow upgrade: Deals damage</html>");
		vineLabel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if(((JLabel) e.getSource()).isEnabled()){
					map.player.pickTrap(new VineTrap());
					picked = true;
				}
			}
		});
		add(vineLabel,gridc);
		
		/*Vine trap cooldown*/
		vineCd = new JLabel("0");
		vineCd.setForeground(Color.black);
		gridc.anchor = GridBagConstraints.CENTER;
		add(vineCd, gridc);
		
		/*Fire trap*/
		gridc.anchor = GridBagConstraints.PAGE_END;
		image = Toolkit.getDefaultToolkit().getImage("Images/firetrap.png");
		fireLabel = new JLabel(new ImageIcon(image));
		/*Tooltip for trap stats*/
		fireLabel.setToolTipText("<html>Sets enemies on fire<br>Rainbow upgrade: Oneshot effect</html>");
		fireLabel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if(((JLabel) e.getSource()).isEnabled()){
					map.player.pickTrap(new FireTrap());
					picked = true;
				}
			}
		});
		add(fireLabel,gridc);
		
		/*Fire trap cooldown*/
		gridc.gridx = j+1;
		gridc.gridy = 7;
		gridc.gridwidth = 1;
		gridc.gridheight = 1;
		gridc.anchor = GridBagConstraints.PAGE_START;
		fireCd = new JLabel("0");
		fireCd.setForeground(Color.black);
		add(fireCd, gridc);
		
		/*Wind trap*/
		gridc.gridx = j+2;
		gridc.gridy = 5;
		gridc.gridwidth = 1;
		gridc.gridheight = 2;
		gridc.anchor = GridBagConstraints.PAGE_START;
		image = Toolkit.getDefaultToolkit().getImage("Images/windtrap.png");
		windLabel = new JLabel(new ImageIcon(image));
		/*Tooltip for trap stats*/
		windLabel.setToolTipText("<html>Knocks back enemies<br>Rainbow upgrade: Slow effect</html>");
		windLabel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if(((JLabel) e.getSource()).isEnabled()){
					map.player.pickTrap(new WindTrap());
					picked = true;
				}
			}
		});
		add(windLabel,gridc);
		
		/*Wind trap cooldown*/
		windCd = new JLabel("0");
		windCd.setForeground(Color.black);
		gridc.anchor = GridBagConstraints.CENTER;
		add(windCd, gridc);
		
		/*Stones*/
		gridc.gridx = j+1;
		gridc.gridy = 7;
		gridc.gridwidth = 2;
		gridc.gridheight = 1;
		gridc.anchor = GridBagConstraints.PAGE_END;
		JLabel stones = new JLabel("Stones");
		add(stones,gridc);	
		
		/*Blue*/
		gridc.gridx = j+1;
		gridc.gridy = 8;
		gridc.gridwidth = 1;
		gridc.gridheight = 1;
		gridc.anchor = GridBagConstraints.CENTER;
		image = Toolkit.getDefaultToolkit().getImage("Images/blue.png");
		blueLabel = new JLabel(new ImageIcon(image));
		/*Tooltip for stone effects*/
		blueLabel.setToolTipText("<html>Increases tower range<br>or<br>trap's affected fields</html>");
		blueLabel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if(((JLabel) e.getSource()).isEnabled()){
					map.player.pickMagicStone(MagicStones.Blue);
					upgrading = true;
				}
			}
		});
		add(blueLabel,gridc);
		
		/*Blue cost*/
		cost = new JLabel("50");
		cost.setForeground(Color.blue);
		gridc.anchor = GridBagConstraints.PAGE_END;
		add(cost, gridc);
		
		/*Yellow*/
		gridc.gridx = j+2;
		gridc.gridy = 8;
		gridc.gridwidth = 1;
		gridc.gridheight = 1;
		gridc.anchor = GridBagConstraints.CENTER;
		image = Toolkit.getDefaultToolkit().getImage("Images/yellow.png");
		yellowLabel = new JLabel(new ImageIcon(image));
		/*Tooltip for stone effects*/
		yellowLabel.setToolTipText("<html>Increases tower speed<br>or<br>Decreases trap cooldown</html>");
		yellowLabel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if(((JLabel) e.getSource()).isEnabled()){
					map.player.pickMagicStone(MagicStones.Yellow);
					upgrading = true;
				}
			}
		});
		add(yellowLabel,gridc);
		
		/*Yellow cost*/
		cost = new JLabel("50");
		cost.setForeground(Color.blue);
		gridc.anchor = GridBagConstraints.PAGE_END;
		add(cost, gridc);
		
		/*Red*/
		gridc.gridx = j+1;
		gridc.gridy = 9;
		gridc.gridwidth = 1;
		gridc.gridheight = 1;
		gridc.anchor = GridBagConstraints.CENTER;
		image = Toolkit.getDefaultToolkit().getImage("Images/red.png");
		redLabel = new JLabel(new ImageIcon(image));
		/*Tooltip for stone effects*/
		redLabel.setToolTipText("<html>Increases tower damage<br>or<br>Trap effect level</html>");
		redLabel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if(((JLabel) e.getSource()).isEnabled()){
					map.player.pickMagicStone(MagicStones.Red);
					upgrading = true;
				}
			}
		});
		add(redLabel,gridc);
		
		/*Red cost*/
		cost = new JLabel("60");
		cost.setForeground(Color.blue);
		gridc.anchor = GridBagConstraints.PAGE_END;
		add(cost, gridc);
		
		/*Rainbow*/
		gridc.gridx = j+2;
		gridc.gridy = 9;
		gridc.gridwidth = 1;
		gridc.gridheight = 1;
		gridc.anchor = GridBagConstraints.CENTER;
		image = Toolkit.getDefaultToolkit().getImage("Images/rainbow.png");
		rainbowLabel = new JLabel(new ImageIcon(image));
		/*Tooltip for stone effects*/
		rainbowLabel.setToolTipText("<html>Read each of<br> defense's tooltips<br> for rainbow effects</html>");
		rainbowLabel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if(((JLabel) e.getSource()).isEnabled()){
					map.player.pickMagicStone(MagicStones.Rainbow);
					upgrading = true;
				}
			}
		});
		add(rainbowLabel,gridc);
		
		/*Rainbow cost*/
		cost = new JLabel("100");
		cost.setForeground(Color.blue);
		gridc.anchor = GridBagConstraints.PAGE_END;
		add(cost, gridc);
		
		update();
		this.pack();
		this.setVisible(true);
	}
	
	/*
	 * Function to manage displayable variables like hp and mana.
	 * Also responsible for enabling and disabling "buttons" in the menu
	 * so the player can only buy the ones he/she has enough mana for.
	 * */
	public void update(){	
		mana.setText("Mana: "+map.player.getMana());
		hp.setText("Hp: "+map.player.getHp());
		vineCd.setText(""+map.vineTrapCD);
		windCd.setText(""+map.windTrapCD);
		fireCd.setText(""+map.fireTrapCD);
		
		/*Disabling and enabling menu items whether we have enough mana or not*/
		if(map.player.getMana()<30){
			oneLabel.setEnabled(false);
		}else{
			oneLabel.setEnabled(true);
		}
		if(map.player.getMana()<40){
			archerLabel.setEnabled(false);
		}else{
			archerLabel.setEnabled(true);
		}
		if(map.player.getMana()<50){
			catapultLabel.setEnabled(false);
			blueLabel.setEnabled(false);
			yellowLabel.setEnabled(false);
		}else{
			catapultLabel.setEnabled(true);
			blueLabel.setEnabled(true);
			yellowLabel.setEnabled(true);
		}
		if(map.player.getMana()<60){
			redLabel.setEnabled(false);
		}else{
			redLabel.setEnabled(true);
		}
		if(map.player.getMana()<70){
			twoLabel.setEnabled(false);
		}else{
			twoLabel.setEnabled(true);
		}
		if(map.player.getMana()<100){
			rainbowLabel.setEnabled(false);
		}else{
			rainbowLabel.setEnabled(true);
		}
		
		/*Disabling and enabling traps whether they cooled down or not*/
		if(Integer.parseInt(vineCd.getText())>0){
			vineLabel.setEnabled(false);
		}else{
			vineLabel.setEnabled(true);
		}
		if(Integer.parseInt(windCd.getText())>0){
			windLabel.setEnabled(false);
		}else{
			windLabel.setEnabled(true);
		}
		if(Integer.parseInt(fireCd.getText())>0){
			fireLabel.setEnabled(false);
		}else{
			fireLabel.setEnabled(true);
		}
		
		if(map.isOver){
			JOptionPane.showMessageDialog(this, map.getReason(), "Game over", JOptionPane.INFORMATION_MESSAGE);
		}
		
		this.setVisible(true);
		//this.repaint();
	}
	
}
